<!--
 * @Description:
 * @Author bianpengfei
 * @create 2022/7/7 12:05
 -->
<template>
  <div class="h-full bg-[#fff]">
    <div class="monitor-wrap">
      <div
        v-for="(item, index) in source.data"
        :key="index"
        class="figure-circle-item"
        :data-id="item.id"
        :style="{ left: `${item.x}px`, top: `${item.y}px` }"
      >
        <div class="figure-circle">
          <span :class="['figure-circle-label', `figure-circle-label--${item.position}`]">{{ item.label }}</span>
        </div>

        <!--        <div v-if="item.position == 'top'" class="figure-circle-item-top">-->
        <!--          <i class="figure-circle" :style="{ left: `${item.x}px`, top: `${item.y}px` }"></i>-->
        <!--        </div>-->

        <!--        <div v-if="item.position == 'right'" class="figure-circle-item-right">-->
        <!--          <i class="figure-circle"></i>-->
        <!--          <span :class="['figure-circle-label']">{{ item.label }}</span>-->
        <!--        </div>-->

        <!--        <div v-if="item.position == 'bottom'" class="figure-circle-item-bottom">-->
        <!--          <i class="figure-circle"></i>-->
        <!--          <span :class="['figure-circle-label']">{{ item.label }}</span>-->
        <!--        </div>-->

        <!--        <div v-if="item.position == 'left'" class="figure-circle-item-left">-->
        <!--          <span :class="['figure-circle-label']">{{ item.label }}</span>-->
        <!--          <i class="figure-circle"></i>-->
        <!--        </div>-->
      </div>

      <div v-for="(item, index) in source.line" :key="`${item.from}_${item.to}_${index}`" class="monitor-line-item">
        <!--        <div class="" :key="index"></div>-->
        <!--        <div class="" :key="index">{{ item.label }}</div>-->
        <!--        <div class="" :key="index"></div>-->

        <template v-for="(cItem, cIndex) in item.dots">
          <div
            :key="cIndex"
            :style="[
              {
                width: '5px',
                height: '5px',
                'border-radius': '50%',
                left: `${cItem.x}px`,
                top: `${cItem.y}px`,
                position: 'absolute',
                'z-index': 100,
                'background-color': 'red'
              }
            ]"
          ></div>
        </template>

        <svg
          xmlns="http://www.w3.org/2000/svg"
          version="1.1"
          style="position: absolute; width: 100%; height: 100%; z-index: 1"
        >
          <!--          <polyline-->
          <!--            points="20,20 40,25 60,40 80,120 120,140 200,180"-->
          <!--            style="fill: none; stroke: black; stroke-width: 3"-->
          <!--          />-->

          <line
            v-for="(cItem, cIndex) in item.lines"
            :key="cIndex"
            :x1="cItem.x1"
            :y1="cItem.y1"
            :x2="cItem.x2"
            :y2="cItem.y2"
            style="stroke: rgb(255, 0, 0); stroke-width: 1"
          />
        </svg>

        <!--        <div-->
        <!--          v-for="(cItem, cIndex) in item.lines"-->
        <!--          :key="cIndex"-->
        <!--          :class="['monitor-line', cIndex == item.lines.length - 1 && `monitor-line-arrow-${cItem.arrow}`]"-->
        <!--          :style="{-->
        <!--            width: `${cItem.width}px`,-->
        <!--            height: `${cItem.height}px`,-->
        <!--            left: `${cItem.x}px`,-->
        <!--            top: `${cItem.y}px`,-->
        <!--            ...(cItem.style || {})-->
        <!--          }"-->
        <!--        ></div>-->
      </div>

      <!--      <div class="monitor__step-1"></div>-->

      <!--      <div class="monitor__step-2"></div>-->

      <!--      <div class="monitor__step-3"></div>-->
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      source: {
        data: [],
        line: []
      }
    }
  },

  mounted() {
    this.source.data = [
      { id: '_1', label: '采集点1', x: 100, y: 100, position: 'bottom', gutter: 10 },
      { id: '_2', label: '存储库2', x: 200, y: 10, position: 'top', gutter: 10 },
      { id: '_3', label: 'hive3', x: 200, y: 110, position: 'right', gutter: 10 },
      { id: '_4', label: 'ods', x: 200, y: 210, position: 'left', gutter: 10 }
    ]
    this.source.line = [
      { from: '_1', to: '_1', label: '传输' },
      { from: '_1', to: '_3', label: '传输' },
      { from: '_1', to: '_3', label: '传输' },
      { from: '_1', to: '_3', label: '传输' }
      // { from: '_1', to: '_4', label: '传输' },
    ]

    this.$ = (k, element = this.$el) => element.querySelector(k)

    this.$$ = (k, element = this.$el) => Array.from(element.querySelectorAll(k) || [])

    this._updateNodePos = (element) => {}

    this.$nextTick(() => {
      this.source.data.forEach((v) => {
        let el = this.$(`[data-id="${v.id}"]`)
        if (el) {
          let offsetW = el.offsetWidth
          let offsetH = el.offsetHeight
          el.cornT = { x: v.x + offsetW / 2, y: v.y }
          el.cornR = { x: v.x + offsetW, y: v.y + offsetH / 2 }
          el.cornB = { x: v.x + offsetW / 2, y: v.y + offsetH }
          el.cornL = { x: v.x, y: v.y + offsetH / 2 }
          v.ele = el
        }
      })

      this._sourceDataObj = this.source.data.reduce((pre, cur) => {
        if (cur.id) pre[cur.id] = Object.freeze(cur)
        return pre
      }, {})

      console.log('monitor@sourceDataObj', this._sourceDataObj)

      const getDotDistance = (dot1, dot2) => {
        return Math.sqrt(Math.abs(dot1.x - dot2.x) ** 2 + Math.abs(dot1.y - dot2.y) ** 2)
      }

      let getNearestDistance = (fromEle, toEle) => {
        let obj = {
          topToTop: { from: fromEle.cornT, to: toEle.cornT, fromPos: 'top', toPos: 'top' },
          topToRight: { from: fromEle.cornT, to: toEle.cornR, fromPos: 'top', toPos: 'right' },
          topToBottom: { from: fromEle.cornT, to: toEle.cornB, fromPos: 'top', toPos: 'bottom' },
          topToLeft: { from: fromEle.cornT, to: toEle.cornL, fromPos: 'top', toPos: 'left' },

          rightToTop: { from: fromEle.cornR, to: toEle.cornT, fromPos: 'right', toPos: 'top' },
          rightToRight: { from: fromEle.cornR, to: toEle.cornR, fromPos: 'right', toPos: 'right' },
          rightToBottom: { from: fromEle.cornR, to: toEle.cornB, fromPos: 'right', toPos: 'bottom' },
          rightToLeft: { from: fromEle.cornR, to: toEle.cornL, fromPos: 'right', toPos: 'left' },

          bottomToTop: { from: fromEle.cornB, to: toEle.cornT, fromPos: 'bottom', toPos: 'top' },
          bottomToRight: { from: fromEle.cornB, to: toEle.cornR, fromPos: 'bottom', toPos: 'right' },
          bottomToBottom: { from: fromEle.cornB, to: toEle.cornB, fromPos: 'bottom', toPos: 'bottom' },
          bottomToLeft: { from: fromEle.cornB, to: toEle.cornL, fromPos: 'bottom', toPos: 'left' },

          leftToTop: { from: fromEle.cornL, to: toEle.cornT, fromPos: 'left', toPos: 'top' },
          leftToRight: { from: fromEle.cornL, to: toEle.cornR, fromPos: 'left', toPos: 'right' },
          leftToBottom: { from: fromEle.cornL, to: toEle.cornB, fromPos: 'left', toPos: 'bottom' },
          leftToLeft: { from: fromEle.cornL, to: toEle.cornL, fromPos: 'left', toPos: 'left' }
        }

        let minDistanceObj
        Object.values(obj)
          .map((v) => {
            v.distance = getDotDistance(v.from, v.to)
            v.fromEle = fromEle
            v.toEle = toEle
            return v
          })
          .forEach((v) => {
            if (!minDistanceObj) {
              minDistanceObj = v
              return
            }
            if (v.distance < minDistanceObj.distance) {
              minDistanceObj = v
            }
          })
        console.log('monitor@打印', obj, minDistanceObj)

        return minDistanceObj
      }

      this.source.line = this.source.line.map((v) => {
        v.fromEle = this._sourceDataObj[v.from]?.ele
        v.toEle = this._sourceDataObj[v.to]?.ele
        let connectInfo = getNearestDistance(v.fromEle, v.toEle)
        if (connectInfo) {
          v.lineWidth = connectInfo.distance
          v.connectInfo = connectInfo
          let lines = []
          let dots = []
          let arrowConf = {
            top: 'down',
            bottom: 'up',
            right: 'left',
            left: 'right'
          }
          let gutterW = connectInfo.to.x - connectInfo.from.x
          let gutterH = connectInfo.to.y - connectInfo.from.y
          let halfWidth = Math.abs(gutterW) / 2
          let halfHeight = Math.abs(gutterH) / 2
          if (connectInfo.from.x == connectInfo.to.x) {
            // 只有一条线
            lines.push({
              x: connectInfo.from.x,
              y: connectInfo.from.y,
              width: 1,
              height: Math.abs(gutterH),
              arrow: arrowConf[connectInfo.toPos],
              style: {
                transform: `rotate(${connectInfo.from.y < connectInfo.to.y ? '0deg' : '180deg'})`
              }
            })
          } else if (connectInfo.from.y == connectInfo.to.y) {
            // 只有一条线  20
            lines.push({
              x1: connectInfo.from.x,
              y1: connectInfo.from.y,
              x2: connectInfo.to.x,
              y2: connectInfo.to.y,

              x: connectInfo.from.x,
              y: connectInfo.from.y,
              width: Math.abs(gutterW),
              height: 1,
              arrow: arrowConf[connectInfo.toPos],
              style: {
                transform: `rotate(${connectInfo.from.x < connectInfo.to.x ? '0deg' : '180deg'})`,
                transformOrigin: `${connectInfo.from.x < connectInfo.to.x ? 'right' : 'left'}`
              }
            })
          } else {
            let startNext,
              endPre,
              offset = 30,
              circleRadius = 20
            let { from, to, fromPos, toPos, fromEle, toEle } = connectInfo
            switch (fromPos) {
              case 'top': {
                startNext = { x: from.x, y: from.y - offset }
                break
              }
              case 'right': {
                startNext = { x: from.x + offset, y: from.y }
                break
              }
              case 'bottom': {
                startNext = { x: from.x, y: from.y + offset }
                break
              }
              case 'left': {
                startNext = { x: from.x - offset, y: from.y }
                break
              }
            }

            switch (toPos) {
              case 'top': {
                endPre = { x: to.x, y: to.y - offset }
                break
              }
              case 'right': {
                endPre = { x: to.x + to, y: to.y }
                break
              }
              case 'bottom': {
                endPre = { x: to.x, y: to.y + offset }
                break
              }
              case 'left': {
                endPre = { x: to.x - offset, y: to.y }
                break
              }
            }

            let SBbox = [
              { x: fromEle.top - circleRadius + offset, y: fromEle.top + offset },
              { x: fromEle.top + circleRadius + offset, y: fromEle.top + offset },
              { x: fromEle.bottom + circleRadius + offset, y: fromEle.bottom + offset },
              { x: fromEle.top - circleRadius + offset, y: fromEle.bottom + offset }
            ]
            let SBboxXList = SBbox.map((v) => v.x)
            let SBboxYList = SBbox.map((v) => v.y)
            let SBboxMax = {
              xMin: Math.min(...SBboxXList),
              xMax: Math.max(...SBboxXList),
              yMin: Math.min(...SBboxYList),
              yMax: Math.max(...SBboxYList)
            }

            let EBbox = [
              { x: toEle.top - circleRadius + offset, y: toEle.top + offset },
              { x: toEle.top + circleRadius + offset, y: toEle.top + offset },
              { x: toEle.bottom + circleRadius + offset, y: toEle.bottom + offset },
              { x: toEle.top - circleRadius + offset, y: toEle.bottom + offset }
            ]
            let EBboxXList = EBbox.map((v) => v.x)
            let EBboxYList = EBbox.map((v) => v.y)
            let EBboxMax = {
              xMin: Math.min(...EBboxXList),
              xMax: Math.max(...EBboxXList),
              yMin: Math.min(...EBboxYList),
              yMax: Math.max(...EBboxYList)
            }

            let LBbox = [
              { x: startNext.x, y: startNext.y },
              { x: endPre.x, y: startNext.y },
              { x: endPre.x, y: endPre.y },
              { x: startNext.x, y: endPre.y }
            ]

            // tdo 所经过的可能的8个点
            let SLBbox = [
              { x: startNext.x - circleRadius - offset, y: startNext.y },
              { x: endPre.x, y: startNext.y },
              { x: endPre.x, y: endPre.y },
              { x: startNext.x - circleRadius - offset, y: endPre.y }
            ]

            let ELBbox = [
              { x: startNext.x, y: startNext.y },
              { x: endPre.x + offset + circleRadius, y: startNext.y },
              { x: endPre.x + offset + circleRadius, y: endPre.y + 2 * offset + 2 * circleRadius },
              { x: startNext.x, y: endPre.y + 2 * offset + 2 * circleRadius }
            ]
            let centerDot = {
              x: startNext.x + (endPre.x - startNext.x) / 2,
              y: startNext.y + (endPre.y - startNext.y) / 2
            }

            let centerLBboxDots = [
              { x: centerDot.x, y: LBbox[0].y },
              { x: LBbox[1].x, y: centerDot.y },
              { x: centerDot.x, y: LBbox[2].y },
              { x: LBbox[3].x, y: centerDot.y }
            ]

            let centerSLBboxDots = [
              { x: centerDot.x, y: SLBbox[0].y },
              { x: SLBbox[1].x, y: centerDot.y },
              { x: centerDot.x, y: SLBbox[2].y },
              { x: SLBbox[3].x, y: centerDot.y }
            ]

            let centerELBboxDots = [
              { x: centerDot.x, y: ELBbox[0].y },
              { x: ELBbox[1].x, y: centerDot.y },
              { x: centerDot.x, y: ELBbox[2].y },
              { x: ELBbox[3].x, y: centerDot.y }
            ]

            let mergeCenterDots = centerLBboxDots.concat(centerSLBboxDots).concat(centerELBboxDots)

            // mergeCenterDots = mergeCenterDots.filter(v => {
            //   const cond1 = v.x >= SBboxMax.xMin && v.x <= SBboxMax.xMax && v.y >= SBboxMax.yMin && v.y <= SBboxMax.yMax
            //   const cond2 = v.x >= EBboxMax.xMin && v.x <= EBboxMax.xMax && v.y >= EBboxMax.yMin && v.y <= EBboxMax.yMax
            //   if (cond1 && cond2) {
            //     return false
            //   }
            //   return true
            // })

            // mergeCenterDots = Object.values(
            //   mergeCenterDots.reduce((pre, cur) => {
            //     pre[`${cur.x}_${cur.y}`] = cur
            //     return pre
            //   }, {})
            // )
            console.log('mergeCenterDots', mergeCenterDots)

            // from, to, startNext, endPre,

            let g = 0,
              h = 0,
              f = g + h

            const fn = (start, end, list, result = []) => {
              let nodes = list.filter((v) => !v.hasUsed && (v.x == start.x || v.y == start.y))

              if (nodes.length) {
                nodes = nodes.map((v) => {
                  let gV = Math.abs(v.x - start.x)
                  let hV = Math.abs(v.y - end.y)
                  v.diff = gV + hV
                  return v
                })

                let minDiffObj,
                  minDiffObjList = []
                for (let i = 0, len = nodes.length; i < len; i++) {
                  let item = nodes[i]
                  if (!minDiffObj) {
                    minDiffObj = item
                    continue
                  }
                  if (item.diff < minDiffObj.diff) {
                    minDiffObj = item
                    minDiffObjList.push(item)
                  }
                }

                minDiffObj = null
                for (let i = 0, len = minDiffObjList.length; i < len; i++) {
                  let item = minDiffObjList[i]
                  if (!minDiffObj) {
                    minDiffObj = item
                    continue
                  }
                  let itemDiff = Math.abs(item.x - start.x) + Math.abs(item.y - start.y)
                  let minDiff = Math.abs(minDiffObj.x - start.x) + Math.abs(minDiffObj.y - start.y)
                  if (itemDiff < minDiff) {
                    minDiffObj = item
                  }
                }

                console.log('结果@2', start, nodes, minDiffObj)

                console.log('打印输出', minDiffObj, minDiffObjList)
                if (minDiffObj) {
                  minDiffObj.hasUsed = true
                  result.push({ x: minDiffObj.x, y: minDiffObj.y, diff: minDiffObj.diff })
                  fn(minDiffObj, end, list, result)
                }
              }

              return result
            }

            let list = fn(startNext, endPre, mergeCenterDots)

            list.unshift(from, startNext)
            list.push(endPre, to)

            console.log('dots', dots)

            let steps = []

            for (let i = 0, len = list.length; i < len; i++) {
              let item = list[i]
              let nextItem = list[i + 1]
              if (nextItem) {
                steps.push({
                  x1: item.x,
                  y1: item.y,
                  x2: nextItem.x,
                  y2: nextItem.y
                })
              }
            }

            lines = steps
            dots = [from, to, startNext, endPre, ...mergeCenterDots]

            console.log('结果', lines)

            // .sort((a, b) => {
            //   if (a.x != b.x) {
            //     return a.x - b.x
            //   }
            //   return a.y - b.y
            // })

            // lines = steps
            //   .map((v, vi) => {
            //     let nextItem = steps[vi + 1]
            //     if (nextItem) {
            //       return {
            //         x1: v.x,
            //         y1: v.y,
            //         x2: nextItem.x,
            //         y2: nextItem.y
            //       }
            //     }
            //   })
            //   .filter(Boolean)

            // let line1 = {
            //   x1: connectInfo.from.x,
            //   y1: connectInfo.from.y,
            //   x2: connectInfo.from.x + gutterW / 2,
            //   y2: connectInfo.from.y,
            //
            //   x: connectInfo.from.x,
            //   y: connectInfo.from.y,
            //   width: halfWidth,
            //   height: 1,
            //   style: {
            //     transform: `rotate(${connectInfo.from.x < connectInfo.to.x ? '0deg' : '180deg'})`
            //   }
            // }
            // let line2 = {
            //   x1: line1.x2,
            //   y1: line1.y2,
            //   x2: line1.x2,
            //   y2: connectInfo.to.y,
            //
            //   x: connectInfo.from.x + (connectInfo.to.x - connectInfo.from.x) / 2,
            //   y: connectInfo.from.y,
            //   width: 1,
            //   height: Math.abs(gutterH),
            //   style: {
            //     transform: `rotate(${connectInfo.from.y < connectInfo.to.x ? '0deg' : '180deg'})`
            //   }
            // }
            // let line3 = {
            //   x1: line2.x2,
            //   y1: line2.y2,
            //   x2: connectInfo.to.x,
            //   y2: connectInfo.to.y,
            //
            //   x: line2.x,
            //   y: connectInfo.to.y,
            //   width: halfWidth,
            //   height: 1,
            //   style: {
            //     transform: `rotate(${connectInfo.from.x < connectInfo.to.x ? '0deg' : '180deg'})`
            //   }
            // }
            // lines.push(line1, line2, line3)
          }
          v.lines = lines
          v.dots = dots
        }
        return v
      })

      // this.
    })
    console.log('monitor', this.source)
  }
}
</script>

<style scoped lang="scss">
.monitor-wrap {
  height: 300px;
  border: 2px dashed #ccc;
  display: flex;
  width: 100%;
  position: relative;
  * {
    box-sizing: border-box;
  }

  .figure-circle-item {
    width: fit-content;
    height: fit-content;
    position: absolute;
    z-index: 10;
    font-size: 0;
    text-align: center;
    $circle-width: 40px;
    $gutter-width: 4px;
    .figure-circle {
      display: inline-block;
      width: $circle-width;
      height: $circle-width;
      border-radius: 50%;
      border: 1px solid #ccc;
    }
    .figure-circle-label {
      font-size: 12px;
      width: $circle-width;
      display: inline-block;
      &.figure-circle-label--top {
        position: absolute;
        bottom: calc(#{$circle-width} + #{$gutter-width});
        left: 0;
        text-align: center;
      }
      &.figure-circle-label--right {
        position: absolute;
        left: calc(#{$circle-width} + #{$gutter-width});
        display: flex;
        align-items: center;
        min-height: $circle-width;
        text-align: left;
      }
      &.figure-circle-label--bottom {
        position: absolute;
        top: calc(#{$circle-width} + #{$gutter-width});
        left: 0;
        text-align: center;
      }
      &.figure-circle-label--left {
        position: absolute;
        right: calc(#{$circle-width} + #{$gutter-width});
        top: 0;
        display: flex;
        align-items: center;
        justify-content: flex-end;
        min-height: $circle-width;
        text-align: right;
      }
    }
    &-top {
      display: flex;
      flex-direction: column;
      justify-content: center;
      .figure-circle-label {
        padding-bottom: 4px;
      }
    }
    &-right {
      display: flex;
      align-items: center;
      .figure-circle-label {
        padding-left: 4px;
      }
    }
    &-bottom {
      display: flex;
      flex-direction: column;
      justify-content: center;
      .figure-circle-label {
        padding-top: 4px;
      }
    }
    &-left {
      display: flex;
      align-items: center;
      .figure-circle-label {
        padding-right: 4px;
      }
    }
  }

  .monitor-line-item {
    .monitor-line {
      position: absolute;
      background: #ccc;
      &:after {
        content: '';
        width: 0;
        height: 0;
        position: absolute;
      }
      &.monitor-line-arrow-up {
        &:after {
          border-top: 6px solid transparent;
          border-right: 6px solid transparent;
          border-bottom: 6px solid red;
          border-left: 6px solid transparent;
          left: 50%;
          transform: translateX(-50%);
          top: -6px;
        }
      }
      &.monitor-line-arrow-down {
        &:after {
          border-top: 6px solid red;
          border-right: 6px solid transparent;
          border-bottom: 6px solid transparent;
          border-left: 6px solid transparent;
          left: 50%;
          transform: translateX(-50%);
          bottom: -6px;
        }
      }
      &.monitor-line-arrow-right {
        &:after {
          border-top: 6px solid transparent;
          border-right: 6px solid transparent;
          border-bottom: 6px solid transparent;
          border-left: 6px solid red;
          top: 50%;
          transform: translateY(-50%);
          right: -6px;
        }
      }
      &.monitor-line-arrow-left {
        &:after {
          border-top: 6px solid transparent;
          border-right: 6px solid red;
          border-bottom: 6px solid transparent;
          border-left: 6px solid transparent;
          top: 50%;
          transform: translateY(-50%);
          left: -6px;
        }
      }
    }
  }

  .monitor__step-1 {
    border-right: 1px solid #ccc;
    flex: 1;
  }
  .monitor__step-2 {
    flex: 3;
  }
  .monitor__step-3 {
    flex: 2;
  }
}
</style>
